﻿/**
 * Stardust Particle Engine
 * 
 * Homepage
 * 	http://code.google.com/p/stardust-particle-engine/
 * 
 * PDF Manual
 * 	http://stardust-particle-engine.googlecode.com/svn/trunk/manual/Stardust%20Particle%20Engine%20Manual.pdf
 */

package {
	import com.bit101.components.PushButton;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import idv.cjcat.stardust.common.clocks.SteadyClock;
	import idv.cjcat.stardust.common.math.StardustMath;
	import idv.cjcat.stardust.threeD.renderers.DisplayObjectRenderer3D;
	
	[SWF(backgroundColor="#FFFFFF", frameRate=60)]
	
	public class Main extends Sprite {
		
		private var emitter:SpikeEmitter;
		private var renderer:DisplayObjectRenderer3D;
		
		public function Main():void {
			//container
			var container:Sprite = new Sprite();
			container.x = container.y = 232.5;
			addChild(container);
			
			//emitter & renderer
			emitter = new SpikeEmitter(new SteadyClock(1));
			renderer = new DisplayObjectRenderer3D(container);
			renderer.addEmitter(emitter);
			
			//pause button
			var pauseBtn:PushButton = new PushButton();
			pauseBtn.x = pauseBtn.y = 10;
			pauseBtn.label = "Pause";
			addChild(pauseBtn);
			pauseBtn.addEventListener(MouseEvent.CLICK, togglePause);
			
			stage.addEventListener(MouseEvent.MOUSE_MOVE, rotateCamera);
			addEventListener(Event.ENTER_FRAME, mainLoop);
			rotateCamera();
		}
		
		private function mainLoop(e:Event):void {
			emitter.step();
		}
		
		private function rotateCamera(e:Event = null):void {
			var theta:Number = 0.55 * (mouseX - 320) * StardustMath.DEGREE_TO_RADIAN;
			var phy:Number = 0.35 * (mouseY - 240) * StardustMath.DEGREE_TO_RADIAN;
			phy = StardustMath.clamp(phy, -0.45 * Math.PI, 0.45 * Math.PI);
			var r:Number = 1000;
			var x:Number = r * Math.sin(theta) * Math.cos(phy);
			var y:Number = r * Math.sin(phy);
			var z:Number = -r * Math.cos(theta) * Math.cos(phy);
			renderer.camera.position.x = x;
			renderer.camera.position.y = y;
			renderer.camera.position.z = z;
			renderer.camera.direction.set( -x, -y, -z);
		}
		
		private function togglePause(e:Event):void {
			var btn:PushButton = e.target as PushButton;
			if (btn.label == "Pause") {
				emitter.active = false;
				emitter.pausibleActions.active = false;
				btn.label = "Resume";
			} else {
				emitter.active = true;
				emitter.pausibleActions.active = true;
				btn.label = "Pause";
			}
		}
	}
}

//------------------------------------------------------------------------------------------------

import flash.display.Shape;
import flash.geom.ColorTransform;
import idv.cjcat.stardust.common.actions.Age;
import idv.cjcat.stardust.common.actions.CompositeAction;
import idv.cjcat.stardust.common.actions.DeathLife;
import idv.cjcat.stardust.common.actions.ScaleCurve;
import idv.cjcat.stardust.common.clocks.Clock;
import idv.cjcat.stardust.common.emitters.Emitter;
import idv.cjcat.stardust.common.initializers.Life;
import idv.cjcat.stardust.common.math.StardustMath;
import idv.cjcat.stardust.common.math.UniformRandom;
import idv.cjcat.stardust.common.particles.Particle;
import idv.cjcat.stardust.threeD.actions.BillboardOriented;
import idv.cjcat.stardust.threeD.actions.CalculateScreenVelocity;
import idv.cjcat.stardust.threeD.actions.Move3D;
import idv.cjcat.stardust.threeD.actions.StardustSpriteUpdate3D;
import idv.cjcat.stardust.threeD.emitters.Emitter3D;
import idv.cjcat.stardust.threeD.initializers.DisplayObjectClass3D;
import idv.cjcat.stardust.threeD.initializers.Velocity3D;
import idv.cjcat.stardust.threeD.zones.SinglePoint3D;
import idv.cjcat.stardust.threeD.zones.SphereShell;
import idv.cjcat.stardust.threeD.zones.SphereSurface;
import idv.cjcat.stardust.twoD.display.StardustSprite;
import idv.cjcat.stardust.twoD.initializers.Position;

//------------------------------------------------------------------------------------------------

//I have no idea why this line must be added in order to compile successfully on Wonderfl.
//Just ignore this class :p
class BugFixer extends Shape { public function BugFixer() { } }

//------------------------------------------------------------------------------------------------

class SpikeEmitter extends Emitter3D {
	
	public var pausibleActions:CompositeAction;
	
	public function SpikeEmitter(clock:Clock) {
		super(clock);
		
		//initializers
		addInitializer(new DisplayObjectClass3D(Spike));
		addInitializer(new Velocity3D(new SphereShell(0, 0, 0, 4, 5)));
		addInitializer(new Life(new UniformRandom(100, 20)));
		
		//actions
		pausibleActions = new CompositeAction();
		
		pausibleActions.addAction(new Age());
		pausibleActions.addAction(new DeathLife());
		pausibleActions.addAction(new Move3D());
		pausibleActions.addAction(new ScaleCurve(10, 20));
		pausibleActions.addAction(new StardustSpriteUpdate3D());
		
		addAction(pausibleActions);
		
		//these two actions cannot be paused
		//they must be executed non-stopped to properly update the billboards orientation
		addAction(new CalculateScreenVelocity());
		addAction(new BillboardOriented());
	}
}

//------------------------------------------------------------------------------------------------

class Spike extends StardustSprite {
	
	public static const WIDTH		:Number = 100;
	public static const HEIGHT		:Number = 150;
	public static const ONE_THIRD	:Number = 1 / 3;
	public static const TWO_THIRD	:Number = 2 / 3;
	public static const INIT_R		:Number = 0xFF;
	public static const INIT_G		:Number = 0xDD;
	public static const INIT_B		:Number = 0x00;
	public static const FINAL_R		:Number = 0xFF;
	public static const FINAL_G		:Number = 0x77;
	public static const FINAL_B		:Number = 0x00;
	
	public function Spike() {
		graphics.beginFill(0);
		graphics.moveTo(0, -HEIGHT * TWO_THIRD);
		graphics.lineTo(0.5 * WIDTH, HEIGHT * ONE_THIRD);
		graphics.lineTo( -0.5 * WIDTH, HEIGHT * ONE_THIRD);
		graphics.lineTo(0, -HEIGHT * TWO_THIRD);
		graphics.endFill();
		
		draw(INIT_R, INIT_G, INIT_B);
	}
	
	override public function update(emitter:Emitter, particle:Particle, time:Number):void {
		var t:Number = particle.initLife - particle.life;
		var r:Number = StardustMath.interpolate(0, INIT_R, particle.initLife, FINAL_R, t);
		var g:Number = StardustMath.interpolate(0, INIT_G, particle.initLife, FINAL_G, t);
		var b:Number = StardustMath.interpolate(0, INIT_B, particle.initLife, FINAL_B, t);
		draw(r, g, b);
	}
	
	private var color:ColorTransform = new ColorTransform();
	private function draw(r:int, g:int, b:int):void {
		color.redOffset = r;
		color.greenOffset = g;
		color.blueOffset = b;
		
		transform.colorTransform = color;
	}
}